package com.smart.community.payment.service.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.smart.community.commons.enums.SystemStatusEnum;
import com.smart.community.commons.result.PageResult;
import com.smart.community.commons.utils.SecurityUtils;
import com.smart.community.feign.property.service.DataScopeFeign;
import com.smart.community.payment.dto.PaymentDTO;
import com.smart.community.payment.entity.Payment;
import com.smart.community.payment.mapper.PaymentMapper;
import com.smart.community.payment.service.IPaymentService;
import com.smart.community.payment.vo.PaymentVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 支付服务实现类
 * 
 * @author Wu.Liang
 * @version 1.0.0
 * @since 2025-06-26
 */
@Slf4j
@Service
@Transactional(rollbackFor = Exception.class)
public class PaymentServiceImpl extends ServiceImpl<PaymentMapper, Payment> implements IPaymentService {

    @Autowired
    private DataScopeFeign dataScopeFeign;

    @Override
    public Payment createPayment(PaymentDTO paymentDTO) throws Exception {
        if (!paymentDTO.validatePayment()) {
            throw new IllegalArgumentException("支付参数校验失败");
        }

        Long currentUserId = SecurityUtils.getCurrentUserId();
        Boolean isSuperAdmin = dataScopeFeign.isUserSuperAdmin(currentUserId);
        if (!isSuperAdmin) {
            Boolean hasPermission = dataScopeFeign.hasPropertyCompanyPermission(currentUserId, paymentDTO.getCommunityId());
            if (!hasPermission) {
                throw new IllegalArgumentException("无权限在该社区创建支付订单");
            }
        }

        Payment payment = new Payment();
        BeanUtils.copyProperties(paymentDTO, payment);
        payment.setBusinessType(convertBusinessTypeToString(paymentDTO.getBusinessType()));
        payment.setOrderNo(paymentDTO.generateOrderNo());
        payment.setPaymentStatus(SystemStatusEnum.DISABLED.getCode());
        payment.setCreateTime(LocalDateTime.now());
        payment.setUpdateTime(LocalDateTime.now());

        if (getBaseMapper().insert(payment) > 0) {
            log.info("创建支付订单成功，订单号: {}", payment.getOrderNo());
            return payment;
        } else {
            throw new RuntimeException("创建支付订单失败");
        }
    }

    @Override
    public PageResult<PaymentVO> pagePayments(PaymentDTO paymentDTO) throws Exception {
        Long currentUserId = SecurityUtils.getCurrentUserId();
        Boolean isSuperAdmin = dataScopeFeign.isUserSuperAdmin(currentUserId);
        
        int current = paymentDTO.getCurrent() != null ? paymentDTO.getCurrent() : 1;
        int size = paymentDTO.getSize() != null ? paymentDTO.getSize() : 10;
        Page<Payment> page = new Page<>(current, size);

        Map<String, Object> params = convertDTOToMap(paymentDTO);
        
        if (!isSuperAdmin) {
            List<Long> communityIds = dataScopeFeign.getUserCommunityIds(currentUserId);
            if (communityIds.isEmpty()) {
                return new PageResult<>(current, size, 0L, new ArrayList<>());
            }
            params.put("communityIds", communityIds);
        }

        IPage<Payment> resultPage = getBaseMapper().selectPaymentPage(page, params);
        List<PaymentVO> voList = convertToVOList(resultPage.getRecords());
        
        return new PageResult<>(current, size, resultPage.getTotal(), voList);
    }

    @Override
    public PaymentVO getPaymentDetail(Long paymentId) throws Exception {
        Long currentUserId = SecurityUtils.getCurrentUserId();
        Payment payment = getBaseMapper().selectById(paymentId);
        
        if (payment != null) {
            Boolean isSuperAdmin = dataScopeFeign.isUserSuperAdmin(currentUserId);
            if (!isSuperAdmin) {
                Boolean hasPermission = dataScopeFeign.hasPropertyCompanyPermission(currentUserId, payment.getCommunityId());
                if (!hasPermission) {
                    throw new IllegalArgumentException("无权限查看该支付订单");
                }
            }
        }
        
        return payment != null ? convertToVO(payment) : null;
    }

    @Override
    public PaymentVO getPaymentByOrderNo(String orderNo) throws Exception {
        Payment payment = getBaseMapper().selectByOrderNo(orderNo);
        
        if (payment != null) {
            Long currentUserId = SecurityUtils.getCurrentUserId();
            Boolean isSuperAdmin = dataScopeFeign.isUserSuperAdmin(currentUserId);
            if (!isSuperAdmin) {
                Boolean hasPermission = dataScopeFeign.hasPropertyCompanyPermission(currentUserId, payment.getCommunityId());
                if (!hasPermission) {
                    throw new IllegalArgumentException("无权限查看该支付订单");
                }
            }
        }
        
        return payment != null ? convertToVO(payment) : null;
    }

    @Override
    public List<PaymentVO> getPaymentsByUserId(Long userId) throws Exception {
        Long currentUserId = SecurityUtils.getCurrentUserId();
        Boolean isSuperAdmin = dataScopeFeign.isUserSuperAdmin(currentUserId);
        if (!isSuperAdmin && !currentUserId.equals(userId)) {
            throw new IllegalArgumentException("无权限查看其他用户的支付记录");
        }
        
        List<Payment> payments = getBaseMapper().selectByUserId(userId);
        return convertToVOList(payments);
    }

    @Override
    public List<PaymentVO> getPaymentsByCommunityId(Long communityId) throws Exception {
        Long currentUserId = SecurityUtils.getCurrentUserId();
        Boolean isSuperAdmin = dataScopeFeign.isUserSuperAdmin(currentUserId);
        if (!isSuperAdmin) {
            Boolean hasPermission = dataScopeFeign.hasPropertyCompanyPermission(currentUserId, communityId);
            if (!hasPermission) {
                throw new IllegalArgumentException("无权限查看该社区的支付记录");
            }
        }
        
        List<Payment> payments = getBaseMapper().selectByCommunityId(communityId);
        return convertToVOList(payments);
    }

    @Override
    public boolean updatePaymentStatus(Long paymentId, Integer paymentStatus) throws Exception {
        Payment payment = getBaseMapper().selectById(paymentId);
        if (payment == null) {
            return false;
        }

        Long currentUserId = SecurityUtils.getCurrentUserId();
        Boolean isSuperAdmin = dataScopeFeign.isUserSuperAdmin(currentUserId);
        if (!isSuperAdmin) {
            Boolean hasPermission = dataScopeFeign.hasPropertyCompanyPermission(currentUserId, payment.getCommunityId());
            if (!hasPermission) {
                throw new IllegalArgumentException("无权限更新该支付订单");
            }
        }

        return getBaseMapper().updatePaymentStatus(paymentId, paymentStatus, LocalDateTime.now()) > 0;
    }

    @Override
    public boolean cancelPayment(Long paymentId, String reason) throws Exception {
        Payment payment = getBaseMapper().selectById(paymentId);
        if (payment == null || !payment.canClose()) {
            return false;
        }

        Long currentUserId = SecurityUtils.getCurrentUserId();
        Boolean isSuperAdmin = dataScopeFeign.isUserSuperAdmin(currentUserId);
        if (!isSuperAdmin) {
            Boolean hasPermission = dataScopeFeign.hasPropertyCompanyPermission(currentUserId, payment.getCommunityId());
            if (!hasPermission) {
                throw new IllegalArgumentException("无权限取消该支付订单");
            }
        }

        payment.setPaymentStatus(SystemStatusEnum.LOCKED.getCode());
        payment.setRemark(reason);
        payment.setUpdateTime(LocalDateTime.now());
        
        return getBaseMapper().updateById(payment) > 0;
    }

    @Override
    public PaymentVO repayPayment(Long paymentId, Integer paymentMethod) throws Exception {
        Payment payment = getBaseMapper().selectById(paymentId);
        if (payment == null || !payment.canRepay()) {
            return null;
        }

        Long currentUserId = SecurityUtils.getCurrentUserId();
        Boolean isSuperAdmin = dataScopeFeign.isUserSuperAdmin(currentUserId);
        if (!isSuperAdmin) {
            Boolean hasPermission = dataScopeFeign.hasPropertyCompanyPermission(currentUserId, payment.getCommunityId());
            if (!hasPermission) {
                throw new IllegalArgumentException("无权限重新支付该订单");
            }
        }

        PaymentDTO paymentDTO = new PaymentDTO();
        paymentDTO.setUserId(payment.getUserId());
        paymentDTO.setCommunityId(payment.getCommunityId());
        paymentDTO.setAmount(payment.getAmount());
        paymentDTO.setPaymentMethod(paymentMethod);
        paymentDTO.setBusinessType(convertBusinessTypeToInteger(payment.getBusinessType()));
        paymentDTO.setBusinessOrderId(payment.getBusinessOrderId());
        paymentDTO.setDescription("重新支付: " + payment.getDescription());

        Payment newPayment = createPayment(paymentDTO);
        return convertToVO(newPayment);
    }

    @Override
    public boolean handlePaymentSuccess(String orderNo, String thirdPartyOrderNo, String channelCode) throws Exception {
        Payment payment = getBaseMapper().selectByOrderNo(orderNo);
        if (payment == null) {
            return false;
        }

        payment.setPaymentStatus(SystemStatusEnum.ENABLED.getCode());
        payment.setPaymentTime(LocalDateTime.now());
        payment.setThirdPartyOrderNo(thirdPartyOrderNo);
        payment.setChannelCode(channelCode);
        payment.setUpdateTime(LocalDateTime.now());

        return getBaseMapper().updateById(payment) > 0;
    }

    @Override
    public boolean handlePaymentFailure(String orderNo, String failureReason) throws Exception {
        Payment payment = getBaseMapper().selectByOrderNo(orderNo);
        if (payment == null) {
            return false;
        }

        payment.setPaymentStatus(SystemStatusEnum.LOCKED.getCode());
        payment.setRemark(failureReason);
        payment.setUpdateTime(LocalDateTime.now());

        return getBaseMapper().updateById(payment) > 0;
    }

    @Override
    public boolean applyRefund(Long paymentId, BigDecimal refundAmount, String refundReason) throws Exception {
        Payment payment = getBaseMapper().selectById(paymentId);
        if (payment == null || !payment.canRefund()) {
            return false;
        }

        if (refundAmount.compareTo(payment.getAmount()) > 0) {
            throw new IllegalArgumentException("退款金额不能大于支付金额");
        }

        Long currentUserId = SecurityUtils.getCurrentUserId();
        Boolean isSuperAdmin = dataScopeFeign.isUserSuperAdmin(currentUserId);
        if (!isSuperAdmin) {
            Boolean hasPermission = dataScopeFeign.hasPropertyCompanyPermission(currentUserId, payment.getCommunityId());
            if (!hasPermission) {
                throw new IllegalArgumentException("无权限申请退款");
            }
        }

        return getBaseMapper().updateRefundInfo(paymentId, refundAmount, refundReason, LocalDateTime.now()) > 0;
    }

    @Override
    public boolean handleRefundSuccess(String orderNo, String refundOrderNo) throws Exception {
        Payment payment = getBaseMapper().selectByOrderNo(orderNo);
        if (payment == null) {
            return false;
        }

        payment.setPaymentStatus(SystemStatusEnum.DELETED.getCode());
        payment.setUpdateTime(LocalDateTime.now());

        return getBaseMapper().updateById(payment) > 0;
    }

    @Override
    public boolean handleRefundFailure(String orderNo, String failureReason) throws Exception {
        Payment payment = getBaseMapper().selectByOrderNo(orderNo);
        if (payment == null) {
            return false;
        }

        payment.setRemark("退款失败: " + failureReason);
        payment.setUpdateTime(LocalDateTime.now());

        return getBaseMapper().updateById(payment) > 0;
    }

    @Override
    public boolean updateThirdPartyInfo(Long paymentId, String thirdPartyOrderNo, String channelCode) throws Exception {
        return getBaseMapper().updateThirdPartyInfo(paymentId, thirdPartyOrderNo, channelCode) > 0;
    }

    @Override
    public List<PaymentVO> getPaymentsByStatus(Integer paymentStatus) throws Exception {
        List<Payment> payments = getBaseMapper().selectByPaymentStatus(paymentStatus);
        return convertToVOList(payments);
    }

    @Override
    public List<PaymentVO> getPaymentsByMethod(Integer paymentMethod) throws Exception {
        List<Payment> payments = getBaseMapper().selectByPaymentMethod(paymentMethod);
        return convertToVOList(payments);
    }

    @Override
    public List<PaymentVO> getPaymentsByTimeRange(LocalDateTime startTime, LocalDateTime endTime) throws Exception {
        List<Payment> payments = getBaseMapper().selectByTimeRange(startTime, endTime);
        return convertToVOList(payments);
    }

    @Override
    public List<PaymentVO> getPaymentsByBusinessOrder(Integer businessType, Long businessOrderId) throws Exception {
        List<Payment> payments = getBaseMapper().selectByBusinessOrder(businessType, businessOrderId);
        return convertToVOList(payments);
    }

    @Override
    public BigDecimal sumAmountByUserId(Long userId) throws Exception {
        return getBaseMapper().sumAmountByUserId(userId);
    }

    @Override
    public BigDecimal sumAmountByCommunityId(Long communityId) throws Exception {
        return getBaseMapper().sumAmountByCommunityId(communityId);
    }

    @Override
    public BigDecimal sumAmountByTimeRange(LocalDateTime startTime, LocalDateTime endTime) throws Exception {
        return getBaseMapper().sumAmountByTimeRange(startTime, endTime);
    }

    @Override
    public List<Map<String, Object>> sumAmountByPaymentMethod(LocalDateTime startTime, LocalDateTime endTime) throws Exception {
        return getBaseMapper().sumAmountByPaymentMethod(startTime, endTime);
    }

    @Override
    public List<Map<String, Object>> sumAmountByBusinessType(LocalDateTime startTime, LocalDateTime endTime) throws Exception {
        return getBaseMapper().sumAmountByBusinessType(startTime, endTime);
    }

    @Override
    public List<Map<String, Object>> countByPaymentStatus(LocalDateTime startTime, LocalDateTime endTime) throws Exception {
        return getBaseMapper().countByPaymentStatus(startTime, endTime);
    }

    @Override
    public List<Map<String, Object>> getDailyPaymentTrend(LocalDateTime startDate, LocalDateTime endDate) throws Exception {
        return getBaseMapper().selectDailyPaymentTrend(startDate, endDate);
    }

    @Override
    public List<Map<String, Object>> getMonthlyPaymentTrend(LocalDateTime startDate, LocalDateTime endDate) throws Exception {
        return getBaseMapper().selectMonthlyPaymentTrend(startDate, endDate);
    }

    @Override
    public Map<String, Object> getPaymentOverview(Long communityId) throws Exception {
        Long currentUserId = SecurityUtils.getCurrentUserId();
        Boolean isSuperAdmin = dataScopeFeign.isUserSuperAdmin(currentUserId);
        if (!isSuperAdmin) {
            Boolean hasPermission = dataScopeFeign.hasPropertyCompanyPermission(currentUserId, communityId);
            if (!hasPermission) {
                throw new IllegalArgumentException("无权限查看该社区的支付概览");
            }
        }

        Map<String, Object> overview = new HashMap<>();
        overview.put("totalAmount", sumAmountByCommunityId(communityId));
        overview.put("todayAmount", sumTodayPaymentAmount(communityId));
        overview.put("monthAmount", sumMonthPaymentAmount(communityId));
        overview.put("pendingCount", countPendingPayments(communityId));
        return overview;
    }

    @Override
    public BigDecimal sumTodayPaymentAmount(Long communityId) throws Exception {
        return getBaseMapper().sumTodayPaymentAmount(communityId);
    }

    @Override
    public BigDecimal sumMonthPaymentAmount(Long communityId) throws Exception {
        return getBaseMapper().sumMonthPaymentAmount(communityId);
    }

    @Override
    public int countPendingPayments(Long communityId) throws Exception {
        return getBaseMapper().countPendingPayments(communityId);
    }

    @Override
    public Map<String, Integer> batchDeletePayments(List<Long> paymentIds) throws Exception {
        Long currentUserId = SecurityUtils.getCurrentUserId();
        Boolean isSuperAdmin = dataScopeFeign.isUserSuperAdmin(currentUserId);
        
        int success = 0, fail = 0;
        for (Long id : paymentIds) {
            Payment payment = getBaseMapper().selectById(id);
            if (payment != null) {
                if (!isSuperAdmin) {
                    Boolean hasPermission = dataScopeFeign.hasPropertyCompanyPermission(currentUserId, payment.getCommunityId());
                    if (!hasPermission) {
                        fail++;
                        continue;
                    }
                }
                if (removeById(id)) {
                    success++;
                } else {
                    fail++;
                }
            } else {
                fail++;
            }
        }

        Map<String, Integer> result = new HashMap<>();
        result.put("total", paymentIds.size());
        result.put("success", success);
        result.put("fail", fail);
        return result;
    }

    @Override
    public int clearExpiredPayments(LocalDateTime expireTime) throws Exception {
        return getBaseMapper().deleteExpiredPayments(expireTime);
    }

    @Override
    public void clearPaymentCache(Long communityId) throws Exception {
        log.info("清除支付缓存，社区ID: {}", communityId);
    }

    @Override
    public void clearUserPaymentCache(Long userId) throws Exception {
        log.info("清除用户支付缓存，用户ID: {}", userId);
    }

    @Override
    public String exportPayments(PaymentDTO paymentDTO) throws Exception {
        Map<String, Object> params = convertDTOToMap(paymentDTO);
        List<Payment> list = getBaseMapper().selectForExport(params);
        return "支付数据导出完成，共" + list.size() + "条记录";
    }

    @Override
    public String exportStatisticsReport(Long communityId, LocalDateTime startDate, LocalDateTime endDate) throws Exception {
        List<Map<String, Object>> report = getBaseMapper().selectStatisticsReport(communityId, startDate, endDate);
        return "统计报表导出完成，共" + report.size() + "条记录";
    }

    private PaymentVO convertToVO(Payment payment) {
        if (payment == null) {
            return null;
        }
        
        PaymentVO vo = new PaymentVO();
        BeanUtils.copyProperties(payment, vo);
        
        vo.setPaymentMethodName(payment.getPaymentMethodName());
        vo.setPaymentStatusName(payment.getPaymentStatusName());
        vo.setBusinessTypeName(payment.getBusinessTypeName());
        vo.setCanRefund(payment.canRefund());
        vo.setIsRefunded(payment.isRefunded());
        
        return vo;
    }

    private List<PaymentVO> convertToVOList(List<Payment> payments) {
        if (payments == null || payments.isEmpty()) {
            return new ArrayList<>();
        }
        return payments.stream().map(this::convertToVO).collect(Collectors.toList());
    }

    private Map<String, Object> convertDTOToMap(PaymentDTO paymentDTO) {
        Map<String, Object> params = new HashMap<>();
        if (paymentDTO != null) {
            BeanUtils.copyProperties(paymentDTO, params);
        }
        return params;
    }

    private String convertBusinessTypeToString(Integer businessType) {
        if (businessType == null) return "other";
        switch (businessType) {
            case 1: return "property_fee";
            case 2: return "sanitation_fee";
            case 3: return "gas_fee";
            case 4: return "utility_fee";
            default: return "other";
        }
    }

    private Integer convertBusinessTypeToInteger(String businessType) {
        if (businessType == null) return 4;
        switch (businessType) {
            case "property_fee": return 1;
            case "sanitation_fee": return 2;
            case "gas_fee": return 3;
            case "utility_fee": return 4;
            default: return 4;
        }
    }
}
